package com.exchange.employee.service.impl;

import com.exchange.employee.config.ArticleRepository;
import com.exchange.employee.config.EsPage;
import com.exchange.employee.dto.AddArticleDto;
import com.exchange.employee.dto.EsQueryDto;
import com.exchange.employee.dto.UptArticleDto;
import com.exchange.employee.entity.Article;
import com.exchange.employee.service.ArticleService;
import com.exchange.utils.result.CommonResult;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/***
 *                    .::::.
 *                  .::::::::.
 *                 :::::::::::
 *             ..:::::::::::'
 *           '::::::::::::'
 *             .::::::::::
 *        '::::::::::::::..
 *             ..::::::::::::.
 *           ``::::::::::::::::
 *            ::::``:::::::::'        .:::.
 *           ::::'   ':::::'       .::::::::.
 *         .::::'      ::::     .:::::::'::::.
 *        .:::'       :::::  .:::::::::' ':::::.
 *       .::'        :::::.:::::::::'      ':::::.
 *      .::'         ::::::::::::::'         ``::::.
 *  ...:::           ::::::::::::'              ``::.
 * ```` ':.          ':::::::::'                  ::::..
 *                    '.:::::'                    ':'````..
 *
 * @Author liuhai
 * @Date 2020-12-25 09:34:05
 * @Description
 */
@Component
@RefreshScope
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

    @Autowired
    private RestHighLevelClient highLevelClient;

    @Value("${params.es.nameMath}")
    private String titleMath;
    @Value("${params.es.aboutMath}")
    private String contentMath;

    private EsPage esPage = new EsPage(1, 5);


    @Override
    public CommonResult getArticleList(EsQueryDto queryDto) throws IOException {
        esPage.setPageNumber(queryDto.getCurrent());
        esPage.setPageSize(queryDto.getPageSize());

        String queryKey = queryDto.getQueryKey();

        Page<Article> restInfo = articleRepository.findByTitleContainsOrContentContains(
                queryKey, titleMath, queryKey, contentMath, esPage);

        QueryBuilder queryBuilders = QueryBuilders.boolQuery()
                //.should(QueryBuilders.matchQuery("title", queryKey)).minimumShouldMatch(titleMath)
                .should(QueryBuilders.matchQuery("content", queryKey)).minimumShouldMatch(contentMath);

        //创建一个新的HighlightBuilder。
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.field("content");
        //如果要多个字段高亮,这项要为false
        highlightBuilder.requireFieldMatch(false);
        highlightBuilder.preTags("<span style='color:red'>");
        highlightBuilder.postTags("</span>");
        //下面这两项,如果你要高亮如文字内容等有很多字的字段,必须配置,不然会导致高亮不全,文章内容缺失等
        highlightBuilder.fragmentSize(800000); //最大高亮分片数
        highlightBuilder.numOfFragments(0); //从第一个分片获取高亮片段

        SearchRequest searchRequest = new SearchRequest();
        //searchRequest.indices("posts");这里可以设计GEET或者POST
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        // 支持按评分排序，评分是指分词之后取得的文档相似度评分
        searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
        searchSourceBuilder.query(queryBuilders);

        int from = (queryDto.getCurrent() -1 ) * queryDto.getPageSize();
        searchSourceBuilder.from(from);
        searchSourceBuilder.size(3);
        searchSourceBuilder.trackTotalHits(true);
        searchSourceBuilder.highlighter(highlightBuilder);
        searchRequest.source(searchSourceBuilder);

        SearchResponse response = highLevelClient.search(searchRequest,RequestOptions.DEFAULT);
        TotalHits totalHits = response.getHits().getTotalHits();
        SearchHit[] hits = response.getHits().getHits();
        List<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit searchHit : hits){
            Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
            //解析高亮字段
            Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
            Set<String> fileSets = highlightFields.keySet();
            if(null != fileSets && fileSets.size() > 0){
                for (String fileName : fileSets){
                    HighlightField field= highlightFields.get(fileName);
                    if(field!= null){
                        Text[] fragments = field.fragments();
                        String n_field = "";
                        for (Text fragment : fragments) {
                            n_field += fragment;
                        }
                        //高亮标题覆盖原标题
                        sourceAsMap.put(fileName, n_field);
                    }
                }
            }
            list.add(sourceAsMap);
        }

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("total", totalHits.value);
        resultMap.put("infoList", list);
        return CommonResult.successWithData("文章信息查询成功", resultMap);
    }

    @Override
    public CommonResult addArticle(AddArticleDto articleDto) {
        Article newArticle = new Article();
        BeanUtils.copyProperties(articleDto, newArticle);
        newArticle = articleRepository.save(newArticle);
        return CommonResult.successWithData("文章添加成功", newArticle);
    }

    @Override
    public CommonResult uptArticle(UptArticleDto articleDto) {
        return null;
    }

    @Override
    public CommonResult delArticle(Long articleId) {
        return null;
    }
}
